<?php
namespace pfp\lib {
    
    \defined('_JEXEC') or die('Restricted access');

    /**
     * Description of pfp_Router
     * 
     * @todo: 
     * 
     * @author George Zeakis<zeageorge@google.com>
     */
    class pfp_Router {

        /**
         *
         * @var array
         */
        protected $_events = array(); 

        /**
         *
         * @var array
         */
        protected $_vars = \NULL;

        /**
         * 
         * @param array $params An assoc array structd:
         *                      array('config'          =>config->pfp->router, 
         *                            'paths'           =>config->pfp->paths, 
         *                            'pfp'             =>pfp object 
         *                              )             
         * @return pfp_Router Returns pfp_Router object or throws an codeExecution_FlowControlException(array('return'=>FALSE)) on error
         */
        public function __construct(array $params){
            $tmp = __FUNCTION__."_tmp"; if (isset($this->_vars["$tmp"])){ unset($this->_vars["$tmp"]); }
            try{
                $this->registerEvents();
                $this->_vars = $params;

                $eventData = array('event_name'=>$this->_events['event_onStart'], 'args'=>&$this->_vars); eventManager::riseEvent($eventData);
            } catch (codeExecution_FlowControlException $exc) {
                $this->_vars["$tmp"]["errors"] = $exc;
                $eventData = array('event_name'=>$this->_events['event_onError'],'args'=>&$this->_vars); eventManager::riseEvent($eventData);
                unset($this->_vars["$tmp"]); 
                throw new codeExecution_FlowControlException(array('return'=>\FALSE), $exc->getMessage());
            }
        }

        public function route(){
            $tmp = __FUNCTION__."_tmp"; if (isset($this->_vars["$tmp"])){ unset($this->_vars["$tmp"]); }
            try{
                $this->_vars["$tmp"]["server_request_method"] = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : "";

                $eventData = array('event_name'=>$this->_events['event_onBefore_route'], 'args'=>&$this->_vars); eventManager::riseEvent($eventData);

                if ($this->_vars["$tmp"]["server_request_method"]=='POST'){
                    if (!isset($_POST[$this->_vars["config"]->http->POST_request->request_field->Name()])){
                        $er_msg = "WARNING::POST Request Field is missing";
                        $eventData = array('event_name'=>$this->_events['event_onWarning'],
                                       'args'=>&$this->_vars, "WARNING"=>array("warning_msg"=>$er_msg,),); eventManager::riseEvent($eventData);
                        throw new codeExecution_FlowControlException(array('return'=>\FALSE), "Page not found");
                    } 
                    $this->route_POST_request($_POST[$this->_vars["config"]->http->POST_request->request_field->Name()]);
                } elseif ($this->_vars["$tmp"]["server_request_method"]=='GET') {
                    $arr = $this->parse_GET_request();
                    
                    echo "<pre>";
                    var_dump($arr);
                    
                    // validate_GET_RequestFields returns array('program_name'=>boolean|string, 'controller_name'=>boolean|string, 'action_name'=>boolean|string, etc)
                    $res = $this->validate_GET_RequestFields($arr);
                    $flag = \FALSE;
                    foreach ($res as $key => $value) {
                        if ($value!==\TRUE){
                            $er_msg = "WARNING::GET request [".implode("|", $_GET)."] validation faild with msg:".$value;
                            $eventData = array('event_name'=>$this->_events['event_onWarning'],
                                           'args'=>&$this->_vars, "WARNING"=>array("warning_msg"=>$er_msg,),); eventManager::riseEvent($eventData);
                             $flag = \TRUE;
                        }
                    }
                    if ($flag===\TRUE){
                        throw new codeExecution_FlowControlException(array('return'=>\FALSE), "Page not found");
                    }
                    
                    $this->route_GET_request2($arr);
                } else {
                    $er_msg = "WARNING::Unknown http request";
                    $eventData = array('event_name'=>$this->_events['event_onWarning'],
                                   'args'=>&$this->_vars, "WARNING"=>array("warning_msg"=>$er_msg,),); eventManager::riseEvent($eventData);
                    throw new codeExecution_FlowControlException(array('return'=>\FALSE), "Page not found");
                    //header('HTTP/1.0 404 Not Found'); echo "<h1>404 Not Found</h1>";
                }

                $this->_vars["$tmp"]["GET_Request"] = $arr;
                
                $eventData = array('event_name'=>$this->_events['event_onAfter_route'], 'args'=>&$this->_vars); eventManager::riseEvent($eventData);
                
                if (isset($this->_vars["$tmp"])){ unset($this->_vars["$tmp"]); }
                return \TRUE;
            } catch (codeExecution_FlowControlException $exc) {
                $this->_vars["$tmp"]["errors"] = $exc;
                $eventData = array('event_name'=>$this->_events['event_onError'],'args'=>&$this->_vars); eventManager::riseEvent($eventData);
                unset($this->_vars["$tmp"]);
                throw new codeExecution_FlowControlException(array('return'=>\FALSE), $exc->getMessage());
            }
        }

        private function registerEvents(){
            $this->_events = array(
                'event_onStart'                                          =>'event_onStart',
                'event_onError'                                          =>'event_onError',
                'event_onWarning'                                        =>'event_onWarning',

                'event_onBefore_route'=>'event_onBefore_route',
                'event_onAfter_route'=>'event_onAfter_route',

                'event_onBefore_routeGETrequest'                         =>'event_onBefore_routeGETrequest',
                'event_onAfter_routeGETrequest'                          =>'event_onAfter_routeGETrequest',
                'event_onBefore_validate_GET_RequestFields'              =>'event_onBefore_validate_GET_RequestFields',
                'event_onAfter_validate_GET_RequestFields'               =>'event_onAfter_validate_GET_RequestFields',
                'event_onBefore_checkGET_Request_ProgramName'            =>'event_onBefore_checkGET_Request_ProgramName',
                'event_onAfter_checkGET_Request_ProgramName'             =>'event_onAfter_checkGET_Request_ProgramName',
                'event_onBefore_checkGET_Request_ControllersName'        =>'event_onBefore_checkGET_Request_ControllersName',
                'event_onAfter_checkGET_Request_ControllersName'         =>'event_onAfter_checkGET_Request_ControllersName',
                'event_onBefore_checkGET_Request_ControllersActionName'  =>'event_onBefore_checkGET_Request_ControllersActionName',
                'event_onAfter_checkGET_Request_ControllersActionName'   =>'event_onAfter_checkGET_Request_ControllersActionName',
                'event_onBefore_checkGET_Request_ControllersActionParams'=>'event_onBefore_checkGET_Request_ControllersActionParams',
                'event_onAfter_checkGET_Request_ControllersActionParams' =>'event_onAfter_checkGET_Request_ControllersActionParams',
                'event_onBefore_parse_GET_request'=>'event_onBefore_parse_GET_request',
                'event_onAfter_parse_GET_request'=>'event_onAfter_parse_GET_request',
                
                'event_onBefore_route_POST_request'=>'event_onBefore_route_POST_request',
                'event_onAfter_route_POST_request'=>'event_onAfter_route_POST_request',
                ''=>'',
                ''=>'',
                ''=>'',
                ''=>'',
                ''=>'',
                ''=>'',
                ''=>'',
                ''=>'',
            );
            eventManager::registerEvents($this->_events);
        }

        protected function route_POST_request($postRequestField){
            $tmp = __FUNCTION__."_tmp"; if (isset($this->_vars["$tmp"])){ unset($this->_vars["$tmp"]); }
            try{
                $this->_vars["$tmp"]["postRequestField"] = (string)$postRequestField;
                
                $eventData = array('event_name'=>$this->_events['event_onBefore_route_POST_request'], 'args'=>&$this->_vars); eventManager::riseEvent($eventData);
                
                $prf = json_decode($postRequestField, TRUE, 512);
                $this->_vars["$tmp"][""] = \json_decode($this->_vars["$tmp"]["postRequestField"], \TRUE, 512);
                
                
                // I STOP HERE
                
                
                
                
                if (is_null($prf)){
                    $r2c = new responseToClient();
                    $r2c->errors = array("Error::Post Request Field: illigal format, must be in JSON format");
                    $r2c->send();
                    return FALSE;
                    // replace the above, with an Error Controller
                }

                $cprf = $this->checkPOST_RequestFields($prf);
                if ($cprf===TRUE){
                    $controllerName = $prf['controller']['name'];
                    $controllerActionName = $prf['controller']['action']['name'];
                    $controllerActionParam = $prf['controller']['action']['param'];
                    $requestData = $prf['data'];

                    $file = $this->_config->server->paths->controllers['main'].$controllerName.DS.$controllerName.'.php';
                    if (!file_exists($file)){
                        $r2c = new responseToClient();
                        $r2c->errors = array("Error::Controller/Page does not exists");
                        $r2c->send();
                        // replace the above, with an Error Controller
                    } else {
                        $req = array('controllerName'=>$controllerName, 
                                     'controllerActionName'=>$controllerActionName, 
                                     'controllerActionParam'=>$controllerActionParam, 
                                     'requestData'=>$requestData);

                        //here check permissions
                        $req2check = $this->checkPermissions($req);
                        if (!$req2check===TRUE){
                            $r2c = new responseToClient();
                            $r2c->errors = array("Error::Permission/Access denied");
                            $r2c->send();
                            return FALSE;
                            // replace the above, with an Error Controller
                        }

                        require_once $file;
                        $controller = new $controllerName();
                        $controller->loadModel($controllerName);

                        // calling methods (actions)
                        if (method_exists($controller, $controllerActionName)) {
                            if (strlen($controllerActionParam)>0){
                                $controller->{$controllerActionName}($requestData, $controllerActionParam);
                            } else {
                                $controller->{$controllerActionName}($requestData);
                            }
                        } else {
                            $r2c = new responseToClient();
                            $r2c->errors = array("Error::Controller Object: Action-Method does not exists");
                            $r2c->send();
                            // replace the above, with an Error Controller
                        }
                    }
                } else {
                    $r2c = new responseToClient();
                    $r2c->errors = array("Error::$cprf");
                    $r2c->send();
                    // replace the above, with an Error Controller
                }
                
                $eventData = array('event_name'=>$this->_events['event_onAfter_route_POST_request'], 'args'=>&$this->_vars); eventManager::riseEvent($eventData);
                
            } catch (codeExecution_FlowControlException $exc) {
                $this->_vars["$tmp"]["errors"] = $exc;
                $eventData = array('event_name'=>$this->_events['event_onError'],'args'=>&$this->_vars); eventManager::riseEvent($eventData);
                unset($this->_vars["$tmp"]);
                throw new codeExecution_FlowControlException(array('return'=>\FALSE), $exc->getMessage());
            }
        }

        protected function validate_POST_RequestFields($postRequestField){
    //        $prf = $postRequestField;
    //        
    //        if (!is_array($prf)){
    //            return 'Post Request Field: is not array.';
    //        }
    //        
    //        if (!isset($prf['controller'])){
    //            return 'Post Request Field: Controller Object is missing.';
    //        }
    //        
    //        if (!isset($prf['data'])){
    //            return 'Post Request Field: Data field is missing.';
    //        }
    //        
    //        if (!isset($prf['controller']['name'])){
    //            return 'Post Request Field: Controller Object: Name field is missing.';
    //        }
    //        
    //        if (!isset($prf['controller']['action'])){
    //            return 'Post Request Field: Controller Object: Action Object is missing.';
    //        }
    //        
    //        if (!isset($prf['controller']['action']['name'])){
    //            return 'Post Request Field: Controller Object: Action Object: Name field is missing.';
    //        }
    //        
    //        if (!isset($prf['controller']['action']['param'])){
    //            return 'Post Request Field: Controller Object: Action Object: Param field is missing.';
    //        }
    //        
    //        $ttt = $this->checkPOST_Request_ProgramName($prf['progam']['name']);
    //        if ($ttt!==TRUE){ return $ttt; }
    //        
    //        $ttt = $this->checkPOST_Request_ControllersName($prf['controller']['name']);
    //        if ($ttt!==TRUE){ return $ttt; }
    //        
    //        $ttt = $this->checkPOST_Request_ControllersActionName($prf['controller']['action']['name']);
    //        if ($ttt!==TRUE){ return $ttt; }
    //        
    //        return TRUE;
        }

        protected function checkPOST_Request_ProgramName($programName){
    //        $charsFor_ProgramName = $this->_vars["config"]->allowed_chars_for_program_name_of_POST_request();
    //        
    //        $n = (string) $programName;
    //        
    //        if (strlen($n)<1) {return "Post Request Field: Program Object: Name field is empty.";}
    //        
    //        $len = strlen($n);
    //
    //        for ($i = 0; $i < $len; $i++) {
    //            if (!in_array(substr($n, $i, 1), $charsFor_ProgramName)) { return "Post Request Field: Program Object: Name field contains illegal characters."; }
    //        }
    //
    //        return true;
        }

        protected function checkPOST_Request_ControllersName($controllerName){
    //        $charsFor_ControllerName = $this->_vars["config"]->allowed_chars_for_controller_name_of_POST_request();
    //        
    //        $n = (string) $controllerName;
    //        
    //        if (strlen($n)<1) {return "Post Request Field: Controller Object: Name field is empty.";}
    //        
    //        $len = strlen($n);
    //
    //        for ($i = 0; $i < $len; $i++) {
    //            if (!in_array(substr($n, $i, 1), $charsFor_ControllerName)) { return "Post Request Field: Controller Object: Name field contains illegal characters."; }
    //        }
    //
    //        return true;
        }

        protected function checkPOST_Request_ControllersActionName($actionName){
    //        $charsFor_ActionsName = $this->_vars["config"]->allowed_chars_for_controllers_action_name_of_POST_request();
    //        
    //        $n = (string) $actionName;
    //        
    //        if (strlen($n)<1) {return "Post Request Field: Controller Object: Action Object: Name field is empty.";}
    //        
    //        $len = strlen($n);
    //
    //        for ($i = 0; $i < $len; $i++) {
    //            if (!in_array(substr($n, $i, 1), $charsFor_ActionsName)) { return "Post Request Field: Controller Object: Action Object: Name field contains illegal characters."; }
    //        }
    //
    //        return true;
        }

        protected function route_GET_request2(array $GET_Request){
            $tmp = __FUNCTION__."_tmp"; if (isset($this->_vars["$tmp"])){ unset($this->_vars["$tmp"]); }
            try{
                $this->_vars["$tmp"]["GET_Request"] = $GET_Request;
                
                $eventData = array('event_name'=>$this->_events['event_onBefore_routeGETrequest'], 'args'=>&$this->_vars); eventManager::riseEvent($eventData);
                
                $eventData = array('event_name'=>$this->_events['event_onAfter_routeGETrequest'], 'args'=>&$this->_vars); eventManager::riseEvent($eventData);
                
            } catch (codeExecution_FlowControlException $exc) {
                $this->_vars["$tmp"]["errors"] = $exc;
                $eventData = array('event_name'=>$this->_events['event_onError'],'args'=>&$this->_vars); eventManager::riseEvent($eventData);
                unset($this->_vars["$tmp"]); 
                throw new codeExecution_FlowControlException(array('return'=>\FALSE), $exc->getMessage());
            }
        }
        
        /**
         * 
         * @return array 
         * @throws codeExecution_FlowControlException
         */
        protected function parse_GET_request(){
            $tmp = __FUNCTION__."_tmp"; if (isset($this->_vars["$tmp"])){ unset($this->_vars["$tmp"]); }
            try{
                if (!isset($_GET[$this->_vars["config"]->http->GET_request->request_field->Name()])){
                    $er_msg = "WARNING::GET Request Field is missing";
                    $eventData = array('event_name'=>$this->_events['event_onWarning'],
                                   'args'=>&$this->_vars, "WARNING"=>array("warning_msg"=>$er_msg,),); eventManager::riseEvent($eventData);
                    throw new codeExecution_FlowControlException(array('return'=>\FALSE), "Page not found");
                }
                
                if (\count($_GET)!==1){
                    $er_msg = "WARNING::GET Request::Number of parameters NOT equal to 1";
                    $eventData = array('event_name'=>$this->_events['event_onWarning'],
                                   'args'=>&$this->_vars, "WARNING"=>array("warning_msg"=>$er_msg,),); eventManager::riseEvent($eventData);
                    throw new codeExecution_FlowControlException(array('return'=>\FALSE), "Page not found");
                }
                
                $this->_vars["$tmp"]["GET_Request"]["raw"][$this->_vars["config"]->http->GET_request->request_field->Name()] = (string)$_GET[$this->_vars["config"]->http->GET_request->request_field->Name()];

                $getRequestLength = \strlen($this->_vars["$tmp"]["GET_Request"]["raw"][$this->_vars["config"]->http->GET_request->request_field->Name()]);
                if ($getRequestLength < $this->_vars["config"]->http->GET_request->min_length() ||
                    $getRequestLength > $this->_vars["config"]->http->GET_request->max_length()){
                    $er_msg = "WARNING::GET Request:: Request Length out of bounds";
                    $eventData = array('event_name'=>$this->_events['event_onWarning'],
                                   'args'=>&$this->_vars, "WARNING"=>array("warning_msg"=>$er_msg,),); eventManager::riseEvent($eventData);
                    throw new codeExecution_FlowControlException(array('return'=>\FALSE), "Page not found");
                }
                
                $eventData = array('event_name'=>$this->_events['event_onBefore_parse_GET_request'], 'args'=>&$this->_vars); eventManager::riseEvent($eventData);

                $this->_vars["$tmp"]["GET_Request"]["tmp"]     = \ltrim($this->_vars["$tmp"]["GET_Request"]["raw"][$this->_vars["config"]->http->GET_request->request_field->Name()], $this->_vars["config"]->http->GET_request->separator());
                $this->_vars["$tmp"]["GET_Request"]["tmp"]     = \rtrim($this->_vars["$tmp"]["GET_Request"]["tmp"], $this->_vars["config"]->http->GET_request->separator());
//                $this->_vars["$tmp"]["GET_Request"]["tmp"]     = \filter_var($this->_vars["$tmp"]["GET_Request"]["tmp"], \FILTER_SANITIZE_URL);
                $this->_vars["$tmp"]["GET_Request"]["tmp"]     = \explode($this->_vars["config"]->http->GET_request->separator(), $this->_vars["$tmp"]["GET_Request"]["tmp"]);
                
                $numberOf_pieces_of_GET_Request = \count($this->_vars["$tmp"]["GET_Request"]["tmp"]);
                
                if ($numberOf_pieces_of_GET_Request === 3){
                    if ($this->_vars["config"]->http->GET_request->params->minimumNumberOfParameters() > 0){
                        $er_msg = "WARNING::GET Request:: BAD Request: Params are missing and they are required as defined in config";
                        $eventData = array('event_name'=>$this->_events['event_onWarning'],
                                       'args'=>&$this->_vars, "WARNING"=>array("warning_msg"=>$er_msg,),); eventManager::riseEvent($eventData);
                        throw new codeExecution_FlowControlException(array('return'=>\FALSE), "Page not found");
                    }
                } elseif ($numberOf_pieces_of_GET_Request === 4){
                } else {
                    $er_msg = "WARNING::GET Request:: BAD Request: GET Request pieces out of bounds, must be 3 or 4";
                    $eventData = array('event_name'=>$this->_events['event_onWarning'],
                                   'args'=>&$this->_vars, "WARNING"=>array("warning_msg"=>$er_msg,),); eventManager::riseEvent($eventData);
                    throw new codeExecution_FlowControlException(array('return'=>\FALSE), "Page not found");
                }
                
                $this->_vars["$tmp"]["GET_Request"]["program_name"]    = isset($this->_vars["$tmp"]["GET_Request"]["tmp"][0]) ? $this->_vars["$tmp"]["GET_Request"]["tmp"][0] : "";
                $this->_vars["$tmp"]["GET_Request"]["controller_name"] = isset($this->_vars["$tmp"]["GET_Request"]["tmp"][1]) ? $this->_vars["$tmp"]["GET_Request"]["tmp"][1] : "";
                $this->_vars["$tmp"]["GET_Request"]["action_name"]     = isset($this->_vars["$tmp"]["GET_Request"]["tmp"][2]) ? $this->_vars["$tmp"]["GET_Request"]["tmp"][2] : "";
                $this->_vars["$tmp"]["GET_Request"]["action_params"]   = isset($this->_vars["$tmp"]["GET_Request"]["tmp"][3]) ? $this->_vars["$tmp"]["GET_Request"]["tmp"][3] : "";
                
                unset($this->_vars["$tmp"]["GET_Request"]["raw"],$this->_vars["$tmp"]["GET_Request"]["tmp"]);
                
                // action_params_asString
                
                $this->_vars["$tmp"]["GET_Request"]["action_params_"] = \ltrim($this->_vars["$tmp"]["GET_Request"]["action_params"], $this->_vars["config"]->http->GET_request->separator());
                $this->_vars["$tmp"]["GET_Request"]["action_params_"] = \rtrim($this->_vars["$tmp"]["GET_Request"]["action_params_"], $this->_vars["config"]->http->GET_request->separator());
                $this->_vars["$tmp"]["GET_Request"]["action_params_"] = \explode($this->_vars["config"]->http->GET_request->params->separator(),$this->_vars["$tmp"]["GET_Request"]["action_params_"]);
                $this->_vars["$tmp"]["data2return"] = $this->_vars["$tmp"]["GET_Request"];
                
                unset($this->_vars["$tmp"]["GET_Request"], $this->_vars["$tmp"]["data2return"]["action_params"]);

                $eventData = array('event_name'=>$this->_events['event_onAfter_parse_GET_request'], 'args'=>&$this->_vars); eventManager::riseEvent($eventData);
                
                $re = $this->_vars["$tmp"]["data2return"]; unset($this->_vars["$tmp"]);
                return (array)$re;
            } catch (codeExecution_FlowControlException $exc) {
                $this->_vars["$tmp"]["errors"] = $exc;
                $eventData = array('event_name'=>$this->_events['event_onError'],'args'=>&$this->_vars); eventManager::riseEvent($eventData);
                unset($this->_vars["$tmp"]);
                throw new codeExecution_FlowControlException(array('return'=>\FALSE), $exc->getMessage());
            }
        }
        
        protected function route_GET_request($getRequestField){
            $tmp = __FUNCTION__."_tmp"; if (isset($this->_vars["$tmp"])){ unset($this->_vars["$tmp"]); }
            try{
                
                // I STOPED HERE
                
                $this->_vars["$tmp"]["GET_Request"]["raw"]["GET"] = $_GET;
                $this->_vars["$tmp"]["GET_Request"]["raw"][$this->_vars["config"]->http->GET_request->request_field->Name()] = (string)$getRequestField;

                $eventData = array('event_name'=>$this->_events['event_onBefore_routeGETrequest'], 'args'=>&$this->_vars); eventManager::riseEvent($eventData);
                
                $this->_vars["$tmp"]["GET_Request"]["asArray"] = $this->parse_GET_request($this->_vars["$tmp"]["GET_Request"]["raw"][$this->_vars["config"]->http->GET_request->request_field->Name()]);
                
                $this->_vars["$tmp"]["GET_Request"]["program_name"] = 
                        isset($this->_vars["$tmp"]["GET_Request"]["asArray"][0]) ? $this->_vars["$tmp"]["GET_Request"]["asArray"][0] : "";

                $this->_vars["$tmp"]["GET_Request"]["controller_name"] = 
                        isset($this->_vars["$tmp"]["GET_Request"]["asArray"][1]) ? $this->_vars["$tmp"]["GET_Request"]["asArray"][1] : "";

                $this->_vars["$tmp"]["GET_Request"]["action_name"] = 
                        isset($this->_vars["$tmp"]["GET_Request"]["asArray"][2]) ? $this->_vars["$tmp"]["GET_Request"]["asArray"][2] : "";

                unset($this->_vars["$tmp"]["GET_Request"]["raw"]["GET"][$this->_vars["config"]->http->GET_request->request_field->Name()]);

                $this->_vars["$tmp"]["GET_Request"]["action_params"] = array();
                foreach ($this->_vars["$tmp"]["GET_Request"]["raw"]["GET"] as $key => $value) {
                    $this->_vars["$tmp"]["GET_Request"]["action_params"][$key] = $value;
                }

                unset($this->_vars["$tmp"]["GET_Request"]["asArray"]);

                // validate_GET_RequestFields returns array('program_name'=>boolean|string, 'controller_name'=>boolean|string, 'action_name'=>boolean|string,)
                $res = $this->validate_GET_RequestFields($this->_vars["$tmp"]["GET_Request"]);
                foreach ($res as $key => $value) {
                    if ($value!==\TRUE){
                        $er_msg = "WARNING::GET request [".implode("|", $_GET)."] validation faild with msg:".$value;
                        $eventData = array('event_name'=>$this->_events['event_onWarning'],
                                       'args'=>&$this->_vars, "WARNING"=>array("warning_msg"=>$er_msg,),); eventManager::riseEvent($eventData);
                        throw new codeExecution_FlowControlException(array('return'=>\FALSE), "Page not found"); 
                    }
                }

                $this->_vars["$tmp"]["GET_Request"]["action_params_asString"] = "";
                foreach ($this->_vars["$tmp"]["GET_Request"]["raw"]["GET"] as $key => $value) {
                    $this->_vars["$tmp"]["GET_Request"]["action_params_asString"] .= "$key=$value&";
                }
                $this->_vars["$tmp"]["GET_Request"]["action_params_asString"] = \rtrim($this->_vars["$tmp"]["GET_Request"]["action_params_asString"], '&');

                if (!\is_readable($this->_vars["paths"]->progsFolderPath()."prog_".$this->_vars["$tmp"]["GET_Request"]["program_name"])){
                    $er_msg = "WARNING:: Program folder [".$this->_vars["paths"]->progsFolderPath()."prog_".$this->_vars["$tmp"]["GET_Request"]["program_name"]."] not found in file system or is not readable";
                    $eventData = array('event_name'=>$this->_events['event_onWarning'],
                                   'args'=>&$this->_vars, "WARNING"=>array("warning_msg"=>$er_msg,),); eventManager::riseEvent($eventData);
                    throw new codeExecution_FlowControlException(array('return'=>\FALSE), "Page not found");
                }

                $controllerFileName = $this->_vars["paths"]->progsFolderPath() . "prog_" . $this->_vars["$tmp"]["GET_Request"]["program_name"].
                 DS . "controllers" . DS . $this->_vars["$tmp"]["GET_Request"]["controller_name"] . DS . $this->_vars["$tmp"]["GET_Request"]["controller_name"] . ".php";
                if (!\is_readable($controllerFileName)){
                    $er_msg = "WARNING:: controller [$controllerFileName] not found in file system or is not readable";
                    $eventData = array('event_name'=>$this->_events['event_onWarning'],
                                   'args'=>&$this->_vars, "WARNING"=>array("warning_msg"=>$er_msg,),); eventManager::riseEvent($eventData);
                    throw new codeExecution_FlowControlException(array('return'=>\FALSE), "Page not found");
                }
//                echo "<pre>"; var_dump($this->_vars["$tmp"]["GET_Request"]);
                if (permsManager::check($this->_vars["pfp"]->getUser(), "http_GET_Request", $this->_vars["$tmp"]["GET_Request"])===\FALSE){
                    $er_msg = "WARNING:: Permission denied:: User does NOT have permissions to access this resource [".  implode("|", $this->_vars["$tmp"]["GET_Request"]["raw"]["GET"])."]";
                    $eventData = array('event_name'=>$this->_events['event_onWarning'],
                                   'args'=>&$this->_vars, "WARNING"=>array("warning_msg"=>$er_msg,),); eventManager::riseEvent($eventData);
                    throw new codeExecution_FlowControlException(array('return'=>\FALSE), "Permission denied:: User does NOT have permissions to access this resource.");
                } else {
                    $progInit_fileName = $this->_vars["paths"]->progsFolderPath() . "prog_" . 
                                         $this->_vars["$tmp"]["GET_Request"]["program_name"].DS.
                                         $this->_vars["$tmp"]["GET_Request"]["program_name"]."Init.php";
                    if (\is_readable($progInit_fileName)){
                        require_once $progInit_fileName;
                        $progInit_class = "prog_".$this->_vars["$tmp"]["GET_Request"]["program_name"]."\\".  // namespace
                                $this->_vars["$tmp"]["GET_Request"]["program_name"]."Init";
                        
                        if (\is_subclass_of($progInit_class, __NAMESPACE__ ."\\progInit", \TRUE)===\TRUE){
                            if (\method_exists($progInit_class, "setInitParams")===\TRUE){
                                $progInit_obj = new $progInit_class();
                                if ($progInit_obj instanceof progInit){
                                    $initParams = array(
                                        "dbAdapter"=>$this->_vars["pfp"]->getDataBase(),
                                        "user"     =>$this->_vars["pfp"]->getUser(),
                                        "config"   =>array(
                                            "dbAdapter_MainDatabaseConnectionData"=>$this->_vars["pfp"]->getConfig()->pfp->storage->database,
                                            "inProductionMode"                    =>$this->_vars["pfp"]->getConfig()->pfp->inProductionMode(),
                                            "requestObject_type"                  =>"http_GET_Request",
                                            "requestObject"                       =>$this->_vars["$tmp"]["GET_Request"],
                                            "programName"                         =>$this->_vars["$tmp"]["GET_Request"]["program_name"],
                                        ),
                                    );
                                    $progInit_obj->setInitParams($initParams);
                                    $returned_value_from_progInit_obj = $progInit_obj->Init();
                                    
                                    require_once $controllerFileName;
                                    $controller_class = "prog_" . $this->_vars["$tmp"]["GET_Request"]["program_name"]."\\controller\\".$this->_vars["$tmp"]["GET_Request"]["controller_name"];
                                    $controller_obj = new $controller_class($returned_value_from_progInit_obj);
                                    
                                    $action = $this->_vars["$tmp"]["GET_Request"]["action_name"];
                                    if (\method_exists($controller_obj, $action)){
                                        if (\count($this->_vars["$tmp"]["GET_Request"]["action_params"])){
                                            $controller_obj->$action($this->_vars["$tmp"]["GET_Request"]["action_params"]);
                                        } else {
                                            $controller_obj->$action();
                                        }
                                    } else {
                                        $er_msg = "WARNING:: Method/Action [$action] of controller [$controllerFileName], does not exists.";
                                        $eventData = array('event_name'=>$this->_events['event_onWarning'],
                                                       'args'=>&$this->_vars, "WARNING"=>array("warning_msg"=>$er_msg,),); eventManager::riseEvent($eventData);
                                        throw new codeExecution_FlowControlException(array('return'=>\FALSE), "Page not found");
                                    }
                                } else {
                                    unset($progInit_obj);
                                    $er_msg = "WARNING:: Object [$progInit_class] must be an instance of Class progInit. It must extends Class progInit.";
                                    $eventData = array('event_name'=>$this->_events['event_onWarning'],
                                       'args'=>&$this->_vars, "WARNING"=>array("warning_msg"=>$er_msg,),); eventManager::riseEvent($eventData);
                                    throw new codeExecution_FlowControlException(array('return'=>\FALSE), "Internal Server error. Please try again later.");
                                }
                            } else {
                                $er_msg = "WARNING:: Class method progInit::setInitParams(array params) is missing.";
                                $eventData = array('event_name'=>$this->_events['event_onWarning'],
                                       'args'=>&$this->_vars, "WARNING"=>array("warning_msg"=>$er_msg,),); eventManager::riseEvent($eventData);
                                throw new codeExecution_FlowControlException(array('return'=>\FALSE), "Internal Server error. Please try again later.");
                            }
                        } else {
                            $er_msg = "WARNING:: Class [$progInit_class] is not a subclass of class [progInit]. Class [$progInit_class] must extends class [progInit].";
                            $eventData = array('event_name'=>$this->_events['event_onWarning'],
                                       'args'=>&$this->_vars, "WARNING"=>array("warning_msg"=>$er_msg,),); eventManager::riseEvent($eventData);
                            throw new codeExecution_FlowControlException(array('return'=>\FALSE), "Internal Server error. Please try again later.");
                        }
                    } else {
                        $er_msg = "WARNING:: Init file [$progInit_fileName] of program [".$this->_vars["$tmp"]["GET_Request"]["program_name"]."] does not exists or is not readable.";
                        $eventData = array('event_name'=>$this->_events['event_onWarning'],
                                       'args'=>&$this->_vars, "WARNING"=>array("warning_msg"=>$er_msg,),); eventManager::riseEvent($eventData);
                        throw new codeExecution_FlowControlException(array('return'=>\FALSE), "Internal Server error. Please try again later.");
                    }
                }

                $eventData = array('event_name'=>$this->_events['event_onAfter_routeGETrequest'], 'args'=>&$this->_vars); eventManager::riseEvent($eventData);
                if (isset($this->_vars["$tmp"])){ unset($this->_vars["$tmp"]); }
                return \TRUE;
            } catch (codeExecution_FlowControlException $exc) {
                $this->_vars["$tmp"]["errors"] = $exc;
                $eventData = array('event_name'=>$this->_events['event_onError'],'args'=>&$this->_vars); eventManager::riseEvent($eventData);
                unset($this->_vars["$tmp"]); 
                throw new codeExecution_FlowControlException(array('return'=>\FALSE), $exc->getMessage());
            }
        }

        /**
         * 
         * @param array $getRequestFields
         * @return array
         * @throws codeExecution_FlowControlException
         */
        protected function validate_GET_RequestFields(array $getRequestFields){
            $tmp = __FUNCTION__."_tmp"; if (isset($this->_vars["$tmp"])){ unset($this->_vars["$tmp"]); }
            try{
                $this->_vars["$tmp"]["getRequest_array"] = $getRequestFields;

                $eventData = array('event_name'=>$this->_events['event_onBefore_validate_GET_RequestFields'], 'args'=>&$this->_vars); eventManager::riseEvent($eventData);

                $this->_vars["$tmp"]["validation_Results"]["program_name"]    = $this->checkGET_Request_ProgramName($this->_vars["$tmp"]["getRequest_array"]['program_name']);
                $this->_vars["$tmp"]["validation_Results"]["controller_name"] = $this->checkGET_Request_ControllersName($this->_vars["$tmp"]["getRequest_array"]['controller_name']);
                $this->_vars["$tmp"]["validation_Results"]["action_name"]     = $this->checkGET_Request_ControllersActionName($this->_vars["$tmp"]["getRequest_array"]['action_name']);
                $this->_vars["$tmp"]["validation_Results"]["action_params"]   = $this->checkGET_Request_ControllersActionParams($this->_vars["$tmp"]["getRequest_array"]['action_params_']);

                $eventData = array('event_name'=>$this->_events['event_onAfter_validate_GET_RequestFields'], 'args'=>&$this->_vars); eventManager::riseEvent($eventData);
                
                $re = $this->_vars["$tmp"]["validation_Results"]; unset($this->_vars["$tmp"]);
                return (array)$re;
            } catch (codeExecution_FlowControlException $exc) {
                $this->_vars["$tmp"]["errors"] = $exc;
                $eventData = array('event_name'=>$this->_events['event_onError'],'args'=>&$this->_vars); eventManager::riseEvent($eventData);
                unset($this->_vars["$tmp"]); 
                throw new codeExecution_FlowControlException(array('return'=>\FALSE), $exc->getMessage());
            }
        }

        /**
         * 
         * @param string $programName
         * @return boolean|string Returns TRUE on validation success, string msg on validation failure, or throws an codeExecution_FlowControlException(array('return'=>FALSE)) on error
         * @throws codeExecution_FlowControlException
         */
        protected function checkGET_Request_ProgramName($programName){
            $tmp = __FUNCTION__."_tmp"; if (isset($this->_vars["$tmp"])){ unset($this->_vars["$tmp"]); }
            try{
                $this->_vars["$tmp"]["programName"]                                   = (string)$programName;
                $this->_vars["$tmp"]["allowed_chars_for_program_name_of_GET_request"] = $this->_vars["config"]->http->GET_request->program->name->allowed_chars();
                $this->_vars["$tmp"]["program_name_min_length"]                       = $this->_vars["config"]->http->GET_request->program->name->min_length();
                $this->_vars["$tmp"]["program_name_max_length"]                       = $this->_vars["config"]->http->GET_request->program->name->max_length();

                $eventData = array('event_name'=>$this->_events['event_onBefore_checkGET_Request_ProgramName'], 'args'=>&$this->_vars); eventManager::riseEvent($eventData);

                $this->_vars["$tmp"]["checkGET_Request_ProgramName_Results"] = \TRUE;
                $len = \strlen($this->_vars["$tmp"]["programName"]);

                if ($len < $this->_vars["$tmp"]["program_name_min_length"] ||
                    $len > $this->_vars["$tmp"]["program_name_max_length"]){
                    $this->_vars["$tmp"]["checkGET_Request_ProgramName_Results"] = "GET Request: Program name field length, out of bounds.";
                } else {
                    for ($i = 0; $i < $len; $i++) {
                        if (!\in_array(\substr($this->_vars["$tmp"]["programName"], $i, 1), $this->_vars["$tmp"]["allowed_chars_for_program_name_of_GET_request"])) { 
                            $this->_vars["$tmp"]["checkGET_Request_ProgramName_Results"] = "GET Request: Program name field contains illegal characters."; 
                            break;
                        }
                    }
                }

                $eventData = array('event_name'=>$this->_events['event_onAfter_checkGET_Request_ProgramName'], 'args'=>&$this->_vars); eventManager::riseEvent($eventData);
                
                $re = $this->_vars["$tmp"]["checkGET_Request_ProgramName_Results"]; unset($this->_vars["$tmp"]);
                return $re;
            } catch (codeExecution_FlowControlException $exc) {
                $this->_vars["$tmp"]["errors"] = $exc;
                $eventData = array('event_name'=>$this->_events['event_onError'],'args'=>&$this->_vars); eventManager::riseEvent($eventData);
                unset($this->_vars["$tmp"]); 
                throw new codeExecution_FlowControlException(array('return'=>\FALSE), $exc->getMessage());
            }
        }

        /**
         * 
         * @param string $controllerName
         * @return boolean|string Returns TRUE on validation success, string msg on validation failure, or throws an codeExecution_FlowControlException(array('return'=>FALSE)) on error
         * @throws codeExecution_FlowControlException
         */
        protected function checkGET_Request_ControllersName($controllerName){
            $tmp = __FUNCTION__."_tmp"; if (isset($this->_vars["$tmp"])){ unset($this->_vars["$tmp"]); }
            try{
                $this->_vars["$tmp"]["controllerName"]                                   = (string)$controllerName;
                $this->_vars["$tmp"]["allowed_chars_for_controller_name_of_GET_request"] = $this->_vars["config"]->http->GET_request->controller->name->allowed_chars();
                $this->_vars["$tmp"]["controller_name_min_length"]                       = $this->_vars["config"]->http->GET_request->controller->name->min_length();
                $this->_vars["$tmp"]["controller_name_max_length"]                       = $this->_vars["config"]->http->GET_request->controller->name->max_length();

                $eventData = array('event_name'=>$this->_events['event_onBefore_checkGET_Request_ControllersName'], 'args'=>&$this->_vars); eventManager::riseEvent($eventData);

                $this->_vars["$tmp"]["checkGET_Request_ControllersName_Results"] = \TRUE;
                $len = \strlen($this->_vars["$tmp"]["controllerName"]);

                if ($len < $this->_vars["$tmp"]["controller_name_min_length"] ||
                    $len > $this->_vars["$tmp"]["controller_name_max_length"]) {
                    $this->_vars["$tmp"]["checkGET_Request_ControllersName_Results"] = "GET Request: Controller name field length, out of bounds.";
                } else {
                    for ($i = 0; $i < $len; $i++) {
                        if (!\in_array(\substr($this->_vars["$tmp"]["controllerName"], $i, 1), $this->_vars["$tmp"]["allowed_chars_for_controller_name_of_GET_request"])) { 
                            $this->_vars["$tmp"]["checkGET_Request_ControllersName_Results"] = "GET Request: Controller name field contains illegal characters."; 
                            break;
                        }
                    }
                }

                $eventData = array('event_name'=>$this->_events['event_onAfter_checkGET_Request_ControllersName'], 'args'=>&$this->_vars); eventManager::riseEvent($eventData);
                
                $re = $this->_vars["$tmp"]["checkGET_Request_ControllersName_Results"]; unset($this->_vars["$tmp"]);
                return $re;
            } catch (codeExecution_FlowControlException $exc) {
                $this->_vars["$tmp"]["errors"] = $exc;
                $eventData = array('event_name'=>$this->_events['event_onError'],'args'=>&$this->_vars); eventManager::riseEvent($eventData);
                unset($this->_vars["$tmp"]); 
                throw new codeExecution_FlowControlException(array('return'=>\FALSE), $exc->getMessage());
            }
        }

        /**
         * 
         * @param string $actionName
         * @return boolean|string Returns TRUE on validation success, string msg on validation failure, or throws an codeExecution_FlowControlException(array('return'=>FALSE)) on error
         * @throws codeExecution_FlowControlException
         */
        protected function checkGET_Request_ControllersActionName($actionName){
            $tmp = __FUNCTION__."_tmp"; if (isset($this->_vars["$tmp"])){ unset($this->_vars["$tmp"]); }
            try{
                $this->_vars["$tmp"]["actionName"]                                               = (string)$actionName;
                $this->_vars["$tmp"]["allowed_chars_for_controllers_action_name_of_GET_request"] = $this->_vars["config"]->http->GET_request->action->name->allowed_chars();
                $this->_vars["$tmp"]["action_name_min_length"]                                   = $this->_vars["config"]->http->GET_request->action->name->min_length();
                $this->_vars["$tmp"]["action_name_max_length"]                                   = $this->_vars["config"]->http->GET_request->action->name->max_length();

                $eventData = array('event_name'=>$this->_events['event_onBefore_checkGET_Request_ControllersActionName'], 'args'=>&$this->_vars); eventManager::riseEvent($eventData);

                $this->_vars["$tmp"]["checkGET_Request_ControllersActionName_Results"] = \TRUE;
                $len = \strlen($this->_vars["$tmp"]["actionName"]);

                if ($len < $this->_vars["$tmp"]["action_name_min_length"] ||
                    $len > $this->_vars["$tmp"]["action_name_max_length"]) {
                    $this->_vars["$tmp"]["checkGET_Request_ControllersActionName_Results"] = "GET Request: Action name field length, out of bounds.";
                } else {
                    for ($i = 0; $i < $len; $i++) {
                        if (!\in_array(\substr($this->_vars["$tmp"]["actionName"], $i, 1), $this->_vars["$tmp"]["allowed_chars_for_controllers_action_name_of_GET_request"])) { 
                            $this->_vars["$tmp"]["checkGET_Request_ControllersActionName_Results"] = "GET Request: Action name field contains illegal characters."; 
                            break;
                        }
                    }
                }

                $eventData = array('event_name'=>$this->_events['event_onAfter_checkGET_Request_ControllersActionName'], 'args'=>&$this->_vars); eventManager::riseEvent($eventData);
                
                $re = $this->_vars["$tmp"]["checkGET_Request_ControllersActionName_Results"]; unset($this->_vars["$tmp"]);
                return $re;
            } catch (codeExecution_FlowControlException $exc) {
                $this->_vars["$tmp"]["errors"] = $exc;
                $eventData = array('event_name'=>$this->_events['event_onError'],'args'=>&$this->_vars); eventManager::riseEvent($eventData);
                unset($this->_vars["$tmp"]); 
                throw new codeExecution_FlowControlException(array('return'=>\FALSE), $exc->getMessage());
            }
        }

        /**
         * 
         * @param array $params
         * @return boolean|string Returns TRUE on validation success, string msg on validation failure, or throws an codeExecution_FlowControlException(array('return'=>FALSE)) on error
         * @throws codeExecution_FlowControlException
         */
        protected function checkGET_Request_ControllersActionParams(array $params){
            $tmp = __FUNCTION__."_tmp"; if (isset($this->_vars["$tmp"])){ unset($this->_vars["$tmp"]); }
            try{
                $this->_vars["$tmp"]["params"]                                        = $params;
                $this->_vars["$tmp"]["allowed_chars_for_params_name_of_GET_request"]  = $this->_vars["config"]->http->GET_request->params->name->allowed_chars();
                $this->_vars["$tmp"]["allowed_chars_for_params_value_of_GET_request"] = $this->_vars["config"]->http->GET_request->params->value->allowed_chars();
                $this->_vars["$tmp"]["params_name_min_length"]                        = $this->_vars["config"]->http->GET_request->params->name->min_length();
                $this->_vars["$tmp"]["params_name_max_length"]                        = $this->_vars["config"]->http->GET_request->params->name->max_length();
                $this->_vars["$tmp"]["params_value_min_length"]                       = $this->_vars["config"]->http->GET_request->params->value->min_length();
                $this->_vars["$tmp"]["params_value_max_length"]                       = $this->_vars["config"]->http->GET_request->params->value->max_length();

                $eventData = array('event_name'=>$this->_events['event_onBefore_checkGET_Request_ControllersActionParams'], 'args'=>&$this->_vars); eventManager::riseEvent($eventData);

                $this->_vars["$tmp"]["checkGET_Request_ControllersActionParams_Results"] = \TRUE;
                foreach ($this->_vars["$tmp"]["params"] as $name => $value) {
                    $name_len = \strlen((string)$name); $value_len = \strlen((string)$value);

                    if ($name_len < $this->_vars["$tmp"]["params_name_min_length"] ||
                        $name_len > $this->_vars["$tmp"]["params_name_max_length"]){
                        $this->_vars["$tmp"]["checkGET_Request_ControllersActionParams_Results"] = "GET Request: Param name field length, out of bounds.";
                        break;
                    }

                    for ($i = 0; $i < $name_len; $i++) {
                        if (!\in_array(\substr((string)$name, $i, 1), $this->_vars["$tmp"]["allowed_chars_for_params_name_of_GET_request"])){
                            $this->_vars["$tmp"]["checkGET_Request_ControllersActionParams_Results"] = "GET Request: Param name field contains illegal characters.";
                            break 2;
                        }
                    }

                    if ($value_len < $this->_vars["$tmp"]["params_value_min_length"] ||
                        $value_len > $this->_vars["$tmp"]["params_value_max_length"]){
                        $this->_vars["$tmp"]["checkGET_Request_ControllersActionParams_Results"] = "GET Request: Param value field length, out of bounds.";
                        break;
                    }

                    for ($i = 0; $i < $value_len; $i++) {
                        if (!\in_array(\substr((string)$value, $i, 1), $this->_vars["$tmp"]["allowed_chars_for_params_value_of_GET_request"])){
                            $this->_vars["$tmp"]["checkGET_Request_ControllersActionParams_Results"] = "GET Request: Param value field contains illegal characters.";
                            break 2;
                        }
                    }
                }

                $eventData = array('event_name'=>$this->_events['event_onAfter_checkGET_Request_ControllersActionParams'], 'args'=>&$this->_vars); eventManager::riseEvent($eventData);
                
                $re = $this->_vars["$tmp"]["checkGET_Request_ControllersActionParams_Results"]; unset($this->_vars["$tmp"]);
                return $re;
            } catch (codeExecution_FlowControlException $exc) {
                $this->_vars["$tmp"]["errors"] = $exc;
                $eventData = array('event_name'=>$this->_events['event_onError'],'args'=>&$this->_vars); eventManager::riseEvent($eventData);
                unset($this->_vars["$tmp"]); 
                throw new codeExecution_FlowControlException(array('return'=>\FALSE), $exc->getMessage());
            }
        }
    }
}
?>
